﻿using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Common;
using SdmxMl.UC;
using SdmxMl.Structure;
using SdmxMl.Manager;

namespace SdmxMl.Panels
{
    /// <summary> Dialog class for DSD skeleton construction </summary>
    public partial class DlgDsdWizard : Form
    {
        #region Constants

        const string CONCEPT_SCHEME_BASIC_SECONDARY_ID = "CS_MEASURES";
        static string CONCEPT_SCHEME_BASIC_SECONDARY_AGENCY = "CH1_SMS";
        const string MEASURE_DIMENSION_CONCEPT_ID = "MEASURE_DIMENSION";
        const string OBS_VALUE_CONCEPT_ID = "OBS_VALUE";

        #endregion


        #region Internal Members

        private UcMlText ucMlText = null;

        enum dsdDomain
        {
            Dimensions,
            Measures,
            Attributes
        }

        #endregion

        #region Constructor

        public DlgDsdWizard()
        {
            InitializeComponent();
            if (SdmxMl.Multiplexor.Mux.IsNewSmsRegistry)
                CONCEPT_SCHEME_BASIC_SECONDARY_AGENCY = "CH1";

            ucMlText = new UcMlText();
            ucMlText.ML = new MultiLang();
            comboBoxTitle.DropDownControl = ucMlText;

            ucDatePickerFrom.Date = string.Empty;
            ucDatePickerTo.Date = string.Empty;

            InitDsdTree();

            buttonAttrib.Enabled = buttonMeasure.Enabled = buttonDimension.Enabled = false;

        }

        private void DlgDsdWizard_Shown(object sender, EventArgs e)
        {
            buttonRefresh_Click(this, EventArgs.Empty);
        }

        #endregion

        #region ConceptScheme list

        /// <summary>Refresh list of availables conceptScheme</summary>
        /// <param name="sender"></param><param name="e"></param>
        private void buttonRefresh_Click(object sender, EventArgs e)
        {
            comboBoxConceptScheme.Items.Clear();
            ArtefactList artList = ReferenceManager.GetArtefactList(SdmxArtefactType.Concepts);
            if (artList == null || artList.Count == 0)
            {
                MessageBox.Show(this, "No ConceptScheme loaded in memory!" + Environment.NewLine +
                "Please load them and press refresh button.", "Caution", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                comboBoxConceptScheme.Items.AddRange(artList.ToArray());
                ConceptSchemeType cst = null;
                if (ReferenceManager.TreeSdmx.SelectedNode != null)
                    cst = ReferenceManager.TreeSdmx.SelectedNode.Tag as ConceptSchemeType;
                if (cst != null)
                    comboBoxConceptScheme.SelectedItem = cst;
                else
                    comboBoxConceptScheme.SelectedItem = comboBoxConceptScheme.Items[0];
            }
        }

        private ConceptSchemeType GetSelectedConceptScheme()
        {
            ConceptSchemeType cst = null;
            if (comboBoxConceptScheme.SelectedItem != null)
                cst = comboBoxConceptScheme.SelectedItem as ConceptSchemeType;

            return cst;
        }

        #endregion

        #region ConceptScheme Tree

        /// <summary> Fill left tree with concept scheme concepts  </summary>
        private void FillConceptSchemeTree()
        {
            treeViewLeft.BeginUpdate();
            treeViewLeft.Nodes.Clear();

            if (comboBoxConceptScheme.SelectedIndex >= 0)
            {
                TreeNode nodeRoot = new TreeNode("ConceptScheme");
                ConceptSchemeType cst = comboBoxConceptScheme.Items[comboBoxConceptScheme.SelectedIndex] as ConceptSchemeType;
                if (cst != null && cst.ConceptList.Count > 0)
                {
                    TreeNode node = cst.FillNode(nodeRoot);
                    foreach (TreeNode n in nodeRoot.Nodes[0].Nodes[0].Nodes)
                        treeViewLeft.Nodes.Add(n);

                    treeViewLeft.ExpandAll();

                    treeViewLeft.SelectedNode = treeViewLeft.Nodes[0];
                    treeViewLeft.SelectedNode.EnsureVisible();
                }
            }
            
            treeViewLeft.EndUpdate();

            buttonAttrib.Enabled = buttonMeasure.Enabled = buttonDimension.Enabled = false;
        }

        private void treeViewLeft_AfterCheck(object sender, TreeViewEventArgs e)
        {
            int count = 0;
            CountCheckedNodes(treeViewLeft.Nodes, ref count);
            buttonAttrib.Enabled = buttonMeasure.Enabled = buttonDimension.Enabled = count > 0;
        }

        private void CountCheckedNodes(TreeNodeCollection nodeCollection, ref int count)
        {
            foreach (TreeNode node in nodeCollection)
            {
                if (node.Checked)
                    ++count;
                CountCheckedNodes(node.Nodes, ref count);
            }
        }

        #endregion

        #region Combo ConceptScheme Events

        private void comboBoxConceptScheme_SelectedIndexChanged(object sender, EventArgs e)
        {
            FillConceptSchemeTree();
            buttonCheckLevel.Enabled = treeViewLeft.Nodes.Count > 0;
        }
        #endregion

        #region Panel resize

        /// <summary> Resize Tree panels</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void panelFlow_Resize(object sender, EventArgs e)
        {
            int middle = this.panelMiddle.Width;
            int width = (this.Width / 2) - middle / 2;
            this.panelLeft.Width = width;
            this.panelRight.Width = width;
        }
        #endregion

        #region DSD artefact Attributes

        /// <summary>Fill DSD artefact with required and optional edited attributes </summary>
        /// <param name="a"></param> <returns></returns>
        private bool FillEditedAttributes(Artefact a)
        {
            bool filled = false;
            // Fill by default with edit Artefact attributes area
            if (a != null)
            {
                a.Id = textBoxID.Text.Trim();
                a.AgencyId = textBoxAgencyId.Text.Trim();

                // Do not bother user if no name, put a default one
                if (ucMlText.ML.IsEmpty)
                {
                    ucMlText.ML.UpdateDefaultText("DSD_Wizard auto generation");
                    comboBoxTitle.Text = ucMlText.ML.GetFirst();
                }

                a.Name = ucMlText.ML;
                a.Name.UpdateForCurrentLanguage(comboBoxTitle.Text);

                a.Version = textBoxVersion.Text.Trim();
                a.ValidFrom = ucDatePickerFrom.Date;
                a.ValidTo = ucDatePickerTo.Date;

                // Now check required are present
                // ID and agency filled ?
                if (a.Id == string.Empty || a.AgencyId == string.Empty || a.Name.IsEmpty)
                {
                    MessageBox.Show("Artefact ID, AgencyID and Name are required !\n", "Caution", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                    filled = true;
            }
            return filled;
        }
        #endregion

        #region DSD Tree

        /// <summary> Construct the 3 domains of dsd as 3 main nodes. </summary>
        private void InitDsdTree()
        {
            treeViewRight.BeginUpdate();
            treeViewRight.Nodes.Clear();
            treeViewRight.Nodes.Add(new TreeNode(dsdDomain.Dimensions.ToString(), (int)dsdDomain.Dimensions, (int)dsdDomain.Dimensions));
            treeViewRight.Nodes.Add(new TreeNode(dsdDomain.Measures.ToString(), (int)dsdDomain.Measures, (int)dsdDomain.Measures));
            treeViewRight.Nodes.Add(new TreeNode(dsdDomain.Attributes.ToString(), (int)dsdDomain.Attributes, (int)dsdDomain.Attributes));
            treeViewRight.EndUpdate();

            treeViewRight.SelectedNode = treeViewRight.Nodes[(int)dsdDomain.Dimensions];
        }

        /// <summary> Get DSD domain node corresponding to selected item </summary>
        /// <returns>the domain node or null if nothing selected</returns>
        private TreeNode GetDsdDomainNode()
        {
            TreeNode nodeParentTarget = null;
            if (treeViewRight.SelectedNode != null)
            {
                nodeParentTarget = treeViewRight.SelectedNode;
                while (nodeParentTarget.Parent != null)
                    nodeParentTarget = nodeParentTarget.Parent;
            }
            return nodeParentTarget;
        }

        /// <summary> Get node representing the Time dimension (if any) </summary>
        /// <returns>The node holding time dimension or null if none</returns>
        private TreeNode GetTimeDimensionNode()
        {
            TreeNode nodeParentTarget = treeViewRight.Nodes[(int)dsdDomain.Dimensions];
            foreach (TreeNode n in nodeParentTarget.Nodes)
                if (n.ImageIndex == 4) // time dim image index
                    return n;
            return null;
        }

        private void treeViewRight_AfterSelect(object sender, TreeViewEventArgs e)
        {
            RefreshStateButtons();
        }

        /// <summary> Control if concept with same ID already present in DSD tree</summary>
        /// <param name="conceptId">the concept id to check for preasence</param>
        /// <returns>True if already one concept with same id</returns>
        private bool ConceptAlreadyPlaced(string conceptId)
        {
            bool used = false;
            for (int i = (int) dsdDomain.Dimensions; i <= (int) dsdDomain.Attributes && !used; i++)
            {
                foreach (TreeNode node in treeViewRight.Nodes[i].Nodes)
                {
                    ConceptRef cr = node.Tag as ConceptRef;
                    if (cr != null && cr.Concept.Id == conceptId)
                    {
                        used = true;
                        break;
                    }
                }
            }
            return used;
        }

        #endregion

        #region Buttons Events

        /// <summary>Specify dimension action as the Timedimension </summary>
        /// <param name="sender"></param><param name="e"></param>
        private void butTimeDimension_Click(object sender, EventArgs e)
        {
            // Ensure selection is in domain dimensions
            TreeNode nodeParentTarget = GetDsdDomainNode();
            if (nodeParentTarget != null && nodeParentTarget == treeViewRight.Nodes[(int)dsdDomain.Dimensions])
            {
                // Remove older if any
                TreeNode nodeTimeDim = GetTimeDimensionNode();
                if (nodeTimeDim != null)
                    nodeTimeDim.ImageIndex = nodeTimeDim.SelectedImageIndex = 3;

                // Mark selected if not same than before
                if (nodeTimeDim != treeViewRight.SelectedNode)
                    treeViewRight.SelectedNode.ImageIndex = treeViewRight.SelectedNode.SelectedImageIndex = 4;
            }
        }

        /// <summary>
        /// Delete selected dimension item or whole collection
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void buttonDeleteDim_Click(object sender, EventArgs e)
        {
            if (treeViewRight.SelectedNode != null)
            {
                if (treeViewRight.SelectedNode.Parent == null)
                    treeViewRight.SelectedNode.Nodes.Clear();
                else
                    treeViewRight.SelectedNode.Parent.Nodes.Remove(treeViewRight.SelectedNode);
            }

            RefreshStateButtons();
        }

        /// <summary> Check or uncheck all concepts in current tree level </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void buttonCheckLevel_Click(object sender, EventArgs e)
        {
            if (treeViewLeft.SelectedNode != null)
            {
                // Retrieve collection where to operate
                TreeNodeCollection nodeCollection = treeViewLeft.SelectedNode.Parent == null ? treeViewLeft.Nodes : treeViewLeft.SelectedNode.Parent.Nodes;

                // if some items checked in level remove them
                bool erased = false;
                bool flagTreatment = false;
                // Flag treatement (SFO)
                if (Control.ModifierKeys == Keys.Control)
                {
                    flagTreatment = true;
                    RecurseForFlags(nodeCollection, true, ref erased);
                }
                else
                {
                    foreach (TreeNode node in nodeCollection)
                    {
                        if (node.Checked)
                        {
                            node.Checked = false;
                            erased = true;
                        }
                    }
                }

                // if nothing checked check all in level
                if (erased == false)
                {
                    if (flagTreatment)
                    {
                        RecurseForFlags(nodeCollection, false, ref erased);
                    }
                    else
                    {
                        foreach (TreeNode node in nodeCollection)
                            node.Checked = true;
                    }
                }
            }
        }

        private void RecurseForFlags(TreeNodeCollection nodeCollection, bool erase, ref bool erased)
        {
            foreach (TreeNode node in nodeCollection)
            {
                ConceptType concept = node.Tag as ConceptType;
                if (concept.Id.EndsWith("_F"))
                {
                    if (node.Checked && erase)
                    {
                        node.Checked = false;
                        erased = true;
                    }
                    else if (node.Checked == false && erase == false)
                        node.Checked = true;
                }

                RecurseForFlags(node.Nodes, erase, ref erased);

            }
        }

        private void buttonTransfer_Click(object sender, EventArgs e)
        {
            Button but = sender as Button;
            if (but == buttonDimension)
                TransferCheckedConcepts(treeViewLeft.Nodes, treeViewRight.Nodes[(int)dsdDomain.Dimensions]);
            else if (but == buttonMeasure)
                TransferCheckedConcepts(treeViewLeft.Nodes, treeViewRight.Nodes[(int)dsdDomain.Measures]);
            else if (but == buttonAttrib)
                TransferCheckedConcepts(treeViewLeft.Nodes, treeViewRight.Nodes[(int)dsdDomain.Attributes]);
            RefreshStateButtons();
        }

        private void TransferCheckedConcepts(TreeNodeCollection nodeCollection, TreeNode nodeParentTarget)
        {
            for (int i = (int)dsdDomain.Dimensions; i <= (int)dsdDomain.Attributes; i++)
            {
                foreach (TreeNode node in nodeCollection)
                {
                    if (node.Checked)
                    {
                        node.Checked = false;
                        ConceptType c = node.Tag as ConceptType;
                        if (c != null && ConceptAlreadyPlaced(c.Id) == false)
                        {
                            TreeNode newNode = new TreeNode(c.ToString(), 3, 3);
                            newNode.Tag = new ConceptRef(GetSelectedConceptScheme(), c);
                            nodeParentTarget.Nodes.Add(newNode);
                            nodeParentTarget.Expand();
                        }
                    }
                    TransferCheckedConcepts(node.Nodes, nodeParentTarget);
                }
            }
        }

        #endregion

        #region Buttons State

        private void RefreshStateButtons()
        {
            // To generate we need at least a dimension and a measure 
            // and the required attributes must be filled
            //ucMlText.ML.UpdateForCurrentLanguage(comboBoxTitle.Text);

            buttonGenerateDsd.Enabled = treeViewRight.Nodes[0].Nodes.Count > 0 &&
                treeViewRight.Nodes[1].Nodes.Count > 0 &&
                textBoxAgencyId.Text.Length > 0 && textBoxID.Text.Length > 0; // && ucMlText.ML.IsEmpty == false;

            butTimeDimension.Enabled = treeViewRight.Nodes[0].Nodes.Count > 0 &&
                treeViewRight.SelectedNode != null && treeViewRight.SelectedNode.Parent == treeViewRight.Nodes[0];

            buttonCheckLevel.Enabled = treeViewLeft.Nodes.Count > 0;
        }
        #endregion

        #region DSD Generation

        private void buttonGenerateDsd_Click(object sender, EventArgs e)
        {
            KeyFamilyType dsd = new KeyFamilyType();
            CodeListType clSecMeasures = null;
            SmManager sm = new SmManager();

            try
            {
                // Ensure DSD artefact has attributes filled
                if (FillEditedAttributes(dsd))
                {
                    sm.PutArtefact(SdmxArtefactType.KeyFamilies, dsd);
                    bool copyCodelistRef = checkBoxCopyCodelistFromConceptInfo.Checked;
                    bool copyFormat = checkBoxCopyFormat.Checked;
                    bool copyVarlistRef = checkBoxCreateCodelist.Checked;
                    // Do we have secondary measures
                    if (treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes.Count > 1)
                    {
                        // Yes create (optionnaly) a codelist and Dimension measure refering codelist created
                        // Also create a conceptscheme for this secondary measure and a dummy observation
                        clSecMeasures = CreateMeasureCodelist(dsd);
                        ConceptSchemeType cstMeasure = CreateSecMeasureScheme(dsd, copyVarlistRef ? clSecMeasures : null);
                        CreateDsdDimensions(dsd, copyCodelistRef, copyFormat);
                        CreateSecondaryMeasures(dsd, cstMeasure, clSecMeasures, copyCodelistRef, copyFormat);
                        CreateDsdAttributes(dsd, copyCodelistRef, copyFormat);

                         if (checkBoxCreateCodelist.Checked)
                            sm.PutArtefact(SdmxArtefactType.CodeLists, clSecMeasures);
                        sm.PutArtefact(SdmxArtefactType.Concepts, cstMeasure);
                    }
                        // Only one observation measure
                    else if (treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes.Count == 1)
                    {
                        CreateDsdDimensions(dsd, copyCodelistRef, copyFormat);
                        CreateDsdAttributes(dsd, copyCodelistRef, copyFormat);
                        // fill primary measure
                        ConceptRef cref = treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes[0].Tag as ConceptRef;
                        dsd.PrimaryMeasure.ConceptInfo.Id = cref.Concept.Id;
                        dsd.PrimaryMeasure.ConceptSchemeInfo.Id = cref.Scheme.Id;
                        dsd.PrimaryMeasure.ConceptSchemeInfo.AgencyId = cref.Scheme.AgencyId;
                        dsd.PrimaryMeasure.ConceptSchemeInfo.Version = cref.Scheme.Version;
                    }

                    bool proceed = true;
                    // Check if already exist in application main tree
                    if (clSecMeasures != null && ReferenceManager.RemoveExistingArtefact(SdmxArtefactType.CodeLists, clSecMeasures, true))
                        proceed = false;

                    if (proceed && ReferenceManager.RemoveExistingArtefact(SdmxArtefactType.KeyFamilies, dsd, true))
                        proceed = false;

                    if (proceed)
                    {
                        // Place in main tree
                        XmlDocument xDoc = sm.GetAsDocument();
                        ReferenceManager.TreeMgr.LoadSdmxArtefact(null, true, xDoc);
                        InitDsdTree();
                   }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }

        }

        private void CreateDsdDimensions(KeyFamilyType dsd, bool copyCodelistRef, bool copyFormat)
        {
            // Time dimension first (if any)
            TreeNode nodeTimeDim = GetTimeDimensionNode();
            if (nodeTimeDim != null)
            {
                TimeDimensionType td = new TimeDimensionType();
                ConceptRef cref = nodeTimeDim.Tag as ConceptRef;
                if (cref == null)
                    throw new ApplicationException("Invalid: empty concept ref detected!");

                td.ConceptInfo.Id = cref.Concept.Id;
                td.ConceptSchemeInfo.Id = cref.Scheme.Id;
                td.ConceptSchemeInfo.AgencyId = cref.Scheme.AgencyId;
                td.ConceptSchemeInfo.Version = cref.Scheme.Version;
                if (copyFormat)
                    td.TextFormat = cref.Concept.TextFormat;

                if (copyCodelistRef)
                {
                    td.CodelistInfo.Id = cref.Concept.CoreRepresentation.Id;
                    td.CodelistInfo.AgencyId = cref.Concept.CoreRepresentation.AgencyId;
                    td.CodelistInfo.Version = cref.Concept.CoreRepresentation.Version;
                }
                dsd.DimensionList.Add(td); 
            }

            foreach (TreeNode node in treeViewRight.Nodes[(int) dsdDomain.Dimensions].Nodes)
            {
                if (node != nodeTimeDim)
                {
                    ConceptRef cref = node.Tag as ConceptRef;
                    DimensionType dim = new DimensionType();
                    dim.ConceptInfo.Id = cref.Concept.Id;
                    dim.ConceptSchemeInfo.Id = cref.Scheme.Id;
                    dim.ConceptSchemeInfo.AgencyId = cref.Scheme.AgencyId;
                    dim.ConceptSchemeInfo.Version = cref.Scheme.Version;
                    dim.DimKind = DimensionType.DimensionKind.Dimension;
                    dsd.DimensionList.Add(dim);

                    if (copyFormat)
                        dim.TextFormat = cref.Concept.TextFormat;

                    if (copyCodelistRef)
                    {
                        dim.CodelistInfo.Id = cref.Concept.CoreRepresentation.Id;
                        dim.CodelistInfo.AgencyId = cref.Concept.CoreRepresentation.AgencyId;
                        dim.CodelistInfo.Version = cref.Concept.CoreRepresentation.Version;
                    }

                }
            }
        }

        private void CreateDsdAttributes(KeyFamilyType dsd, bool copyCodelistRef, bool copyFormat)
        {
            foreach (TreeNode node in treeViewRight.Nodes[(int)dsdDomain.Attributes].Nodes)
            {
                    ConceptRef cref = node.Tag as ConceptRef;
                    AttributeType at = new AttributeType();
                    at.ConceptInfo.Id = cref.Concept.Id;
                    at.ConceptSchemeInfo.Id = cref.Scheme.Id;
                    at.ConceptSchemeInfo.AgencyId = cref.Scheme.AgencyId;
                    at.ConceptSchemeInfo.Version = cref.Scheme.Version;

                    if (copyFormat)
                        at.TextFormat = cref.Concept.TextFormat;

                    if (copyCodelistRef)
                    {
                        at.CodelistInfo.Id = cref.Concept.CoreRepresentation.Id;
                        at.CodelistInfo.AgencyId = cref.Concept.CoreRepresentation.AgencyId;
                        at.CodelistInfo.Version = cref.Concept.CoreRepresentation.Version;
                    }
                
                if (at.ConceptInfo.Id.EndsWith("_F"))
                {
                    string measureId = at.ConceptInfo.Id.Substring(0, at.ConceptInfo.Id.Length - 2);
                    if (HasAssociatedMeasure(measureId))
                    {
                        at.AttachmentLevel = AttributeType.AttachmentLevelType.Observation;
                        at.AttachmentMeasureList.Add(measureId);
                    }
                }
                    dsd.AttributeList.Add(at);
            }
        }

        private bool HasAssociatedMeasure(string measureId)
        {
            bool hasIt = false;
            foreach (TreeNode node in treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes)
            {
                ConceptRef cref = node.Tag as ConceptRef;

                if (cref != null && cref.Concept.Id == measureId)
                {
                    hasIt = true;
                    break;
                }
            }

            return hasIt;
        }

        private void CreateSecondaryMeasures(KeyFamilyType dsd, ConceptSchemeType cstMeasure, CodeListType clSecMeasures, bool copyCodelistRef, bool copyFormat)
        {
            dsd.PrimaryMeasure.ConceptInfo.Id = cstMeasure.ConceptList[0].Id;
            dsd.PrimaryMeasure.ConceptSchemeInfo.Id = cstMeasure.Id;
            dsd.PrimaryMeasure.ConceptSchemeInfo.AgencyId = cstMeasure.AgencyId;
            dsd.PrimaryMeasure.ConceptSchemeInfo.Version = cstMeasure.Version;

            // Add measure dimension
            DimensionType dim = new DimensionType();
            dim.ConceptInfo.Id = cstMeasure.ConceptList[1].Id;
            dim.ConceptSchemeInfo.Id = cstMeasure.Id;
            dim.ConceptSchemeInfo.AgencyId = cstMeasure.AgencyId;
            dim.ConceptSchemeInfo.Version = cstMeasure.Version;
            dim.DimKind = DimensionType.DimensionKind.Measure;
            dsd.DimensionList.Add(dim);

            if (copyCodelistRef)
            {
                ConceptType cMeasure = cstMeasure.ConceptList[1] as ConceptType;
                if (cMeasure != null)
                {
                    dim.CodelistInfo.Id = cMeasure.CoreRepresentation.Id;
                    dim.CodelistInfo.AgencyId = cMeasure.CoreRepresentation.AgencyId;
                    dim.CodelistInfo.Version = cMeasure.CoreRepresentation.Version;

                    // And remove from concept
                    cMeasure.CoreRepresentation.Id = string.Empty;
                    cMeasure.CoreRepresentation.AgencyId = string.Empty;
                    cMeasure.CoreRepresentation.Version = string.Empty;
                }
            }


            foreach (TreeNode node in treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes)
            {
                ConceptRef cref = node.Tag as ConceptRef;
                CrossSectionalMeasureType csm = new CrossSectionalMeasureType();
                csm.Code = cref.Concept.Id;
                csm.ConceptInfo.Id = cref.Concept.Id;
                csm.ConceptSchemeInfo.Id = cref.Scheme.Id;
                csm.ConceptSchemeInfo.AgencyId = cref.Scheme.AgencyId;
                csm.ConceptSchemeInfo.Version = cref.Scheme.Version;
                csm.MeasureDimension = MEASURE_DIMENSION_CONCEPT_ID; // refer The default created DIM measure concept

                if (copyFormat)
                    csm.TextFormat = cref.Concept.TextFormat;

                if (copyCodelistRef)
                {
                    csm.CodelistInfo.Id = cref.Concept.CoreRepresentation.Id;
                    csm.CodelistInfo.AgencyId = cref.Concept.CoreRepresentation.AgencyId;
                    csm.CodelistInfo.Version = cref.Concept.CoreRepresentation.Version;
                }

                dsd.CrossSectionalMeasureList.Add(csm);
            }
        }

        private CodeListType CreateMeasureCodelist(KeyFamilyType dsd)
        {
            CodeListType clt = new CodeListType();
            if (dsd.Id.StartsWith("DSD_") && dsd.Id.Length > 4)
                clt.Id = "CL_" + dsd.Id.Substring(4);
            else
                clt.Id = "CL_" + dsd.Id;
            clt.AgencyId = dsd.AgencyId;
            clt.Version = dsd.Version;

            clt.Name.UpdateDefaultText("Generated codelist of measures for DSD: " + dsd.Id);

            foreach (TreeNode node in treeViewRight.Nodes[(int)dsdDomain.Measures].Nodes)
            {
                ConceptRef cref = node.Tag as ConceptRef;
                CodeType c = new CodeType();
                c.Id = cref.Concept.Id;
                c.Name = cref.Concept.Name.Clone();
                clt.CodeList.Add(c);
            }

            return clt;
        }

        private ConceptSchemeType CreateSecMeasureScheme(KeyFamilyType dsd, CodeListType clSecMeasures)
        {
            ConceptSchemeType cstSec = new ConceptSchemeType();

            cstSec.Id = CONCEPT_SCHEME_BASIC_SECONDARY_ID;
            cstSec.AgencyId = CONCEPT_SCHEME_BASIC_SECONDARY_AGENCY;
            cstSec.Name.UpdateDefaultText("Concepts for secondary measures usage.");

            ConceptType c = new ConceptType();
            c.Id = OBS_VALUE_CONCEPT_ID;
            c.Name.UpdateDefaultText("Dummy observation value");
            cstSec.ConceptList.Add(c);

            c = new ConceptType();
            c.Id = MEASURE_DIMENSION_CONCEPT_ID;
            c.Name.UpdateDefaultText("Concept used to attach secondary measures codelist");
            if (clSecMeasures != null)
            {
                c.CoreRepresentation.AgencyId = clSecMeasures.AgencyId;
                c.CoreRepresentation.Id = clSecMeasures.Id;
                c.CoreRepresentation.Version = clSecMeasures.Version;
            }

            cstSec.ConceptList.Add(c);

            return cstSec;
        }
        #endregion

        #region DSD attributes Textboxes Events

        private void textBox_TextChanged(object sender, EventArgs e)
        {
            RefreshStateButtons();
        }
        #endregion

        #region Text list for selection

        private void buttonLoadTextList_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                textBoxTextFile.Text = openFileDialog.FileName;
            }
        }


        private void buttonApplyTextList_Click(object sender, EventArgs e)
        {
            try
            {
                if (textBoxTextFile.Text.Length > 0)
                {
                    using (StreamReader sr = new StreamReader(textBoxTextFile.Text, Encoding.Default))
                    {
                        string suggestedConceptId = null;
                        while ((suggestedConceptId = sr.ReadLine()) != null)
                        {
                            foreach (TreeNode node in treeViewLeft.Nodes)
                                if (RecurseForSuggestion(suggestedConceptId, node))
                                    break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error");
            }
        }


        private bool RecurseForSuggestion(string suggestedId, TreeNode node)
        {
            ConceptType c = node.Tag as ConceptType;
            if (c != null && c.Id == suggestedId)
            {
                node.Checked = true;
                return true;
            }
            foreach (TreeNode nd in node.Nodes)
            {
                if (RecurseForSuggestion(suggestedId, nd))
                    return true;
            }
            return false;
        }
        #endregion

    }

    #region Helper class to hold references to concept

    internal class ConceptRef
    {
        internal ConceptSchemeType Scheme { get; set; }
        internal ConceptType  Concept { get; set; }

        internal ConceptRef(ConceptSchemeType cst, ConceptType c)
        {
            Scheme = cst;
            Concept = c;
        }
    }
    #endregion

}
